package com.ruoyi.common.utils.file;

import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.MinIOConfig;
import com.ruoyi.common.exception.ServiceException;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.http.Method;

/**
 * MinIO 工具类
 * 
 * @author ruoyi
 */
@Component
public class MinIOUtils
{
    private static final Logger log = LoggerFactory.getLogger(MinIOUtils.class);

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIOConfig minIOConfig;

    /**
     * 判断bucket是否存在
     * 
     * @param bucketName 存储桶名称
     * @return true存在，false不存在
     */
    public boolean bucketExists(String bucketName)
    {
        try
        {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        }
        catch (Exception e)
        {
            log.error("检查存储桶是否存在失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 创建bucket
     * 
     * @param bucketName 存储桶名称
     */
    public void makeBucket(String bucketName)
    {
        try
        {
            if (!bucketExists(bucketName))
            {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                log.info("存储桶 {} 创建成功", bucketName);
            }
        }
        catch (Exception e)
        {
            log.error("创建存储桶失败: {}", e.getMessage());
            throw new ServiceException("创建存储桶失败");
        }
    }

    /**
     * 上传文件
     * 
     * @param file 文件
     * @return 文件访问路径
     */
    public String uploadFile(MultipartFile file)
    {
        return uploadFile(file, minIOConfig.getBucketName());
    }

    /**
     * 上传文件
     * 
     * @param file 文件
     * @param bucketName 存储桶名称
     * @return 文件访问路径
     */
    public String uploadFile(MultipartFile file, String bucketName)
    {
        try
        {
            // 确保存储桶存在
            makeBucket(bucketName);

            // 生成文件名
            String fileName = generateFileName(file.getOriginalFilename());
            
            // 获取文件输入流
            InputStream inputStream = file.getInputStream();
            
            // 上传文件 - 使用7.x版本的API
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build()
            );

            // 返回文件访问路径
            String fileUrl = minIOConfig.getEndpoint() + "/" + bucketName + "/" + fileName;
            log.info("文件上传成功: {}", fileUrl);
            return fileUrl;
        }
        catch (Exception e)
        {
            log.error("文件上传失败: {}", e.getMessage());
            throw new ServiceException("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 删除文件
     * 
     * @param fileName 文件名
     */
    public void removeFile(String fileName)
    {
        removeFile(fileName, minIOConfig.getBucketName());
    }

    /**
     * 删除文件
     * 
     * @param fileName 文件名
     * @param bucketName 存储桶名称
     */
    public void removeFile(String fileName, String bucketName)
    {
        try
        {
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .build()
            );
            log.info("文件删除成功: {}", fileName);
        }
        catch (Exception e)
        {
            log.error("文件删除失败: {}", e.getMessage());
            throw new ServiceException("文件删除失败");
        }
    }

    /**
     * 下载文件
     * 
     * @param fileName 文件名
     * @param response HttpServletResponse
     */
    public void downloadFile(String fileName, HttpServletResponse response)
    {
        downloadFile(fileName, minIOConfig.getBucketName(), response);
    }

    /**
     * 下载文件
     * 
     * @param fileName 文件名
     * @param bucketName 存储桶名称
     * @param response HttpServletResponse
     */
    public void downloadFile(String fileName, String bucketName, HttpServletResponse response)
    {
        try (InputStream inputStream = minioClient.getObject(
            GetObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build()))
        {
            // 设置响应头
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

            // 输出文件流
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1)
            {
                response.getOutputStream().write(buffer, 0, length);
            }
            response.getOutputStream().flush();
        }
        catch (Exception e)
        {
            log.error("文件下载失败: {}", e.getMessage());
            throw new ServiceException("文件下载失败");
        }
    }

    /**
     * 获取文件预签名URL
     * 
     * @param fileName 文件名
     * @param expires 过期时间（秒）
     * @return 预签名URL
     */
    public String getPresignedObjectUrl(String fileName, int expires)
    {
        return getPresignedObjectUrl(fileName, minIOConfig.getBucketName(), expires);
    }

    /**
     * 获取文件预签名URL
     * 
     * @param fileName 文件名
     * @param bucketName 存储桶名称
     * @param expires 过期时间（秒）
     * @return 预签名URL
     */
    public String getPresignedObjectUrl(String fileName, String bucketName, int expires)
    {
        try
        {
            return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(fileName)
                    .expiry(expires)
                    .build()
            );
        }
        catch (Exception e)
        {
            log.error("获取预签名URL失败: {}", e.getMessage());
            throw new ServiceException("获取预签名URL失败");
        }
    }

    /**
     * 生成文件名
     * 
     * @param originalFilename 原始文件名
     * @return 新文件名
     */
    private String generateFileName(String originalFilename)
    {
        // 获取文件扩展名
        String extension = FilenameUtils.getExtension(originalFilename);
        
        // 生成日期路径 (年/月/日)
        String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        
        // 生成UUID文件名
        String uuid = UUID.randomUUID().toString().replace("-", "");
        
        // 组合文件名: 日期路径/UUID.扩展名
        return datePath + "/" + uuid + "." + extension;
    }

    /**
     * 从完整URL中提取文件名
     * 
     * @param fileUrl 完整的文件URL
     * @return 文件名
     */
    public String extractFileName(String fileUrl)
    {
        if (fileUrl != null && fileUrl.contains("/"))
        {
            // 提取bucket名称后的文件路径
            String bucketName = minIOConfig.getBucketName();
            String prefix = minIOConfig.getEndpoint() + "/" + bucketName + "/";
            if (fileUrl.startsWith(prefix))
            {
                return fileUrl.substring(prefix.length());
            }
        }
        return fileUrl;
    }
} 